package com.landun.market.service.impl;

import com.landun.market.exception.BusinessException;
import com.landun.market.exception.DataNotFoundException;
import com.landun.market.pojo.enums.ResponseCode;
import com.landun.market.pojo.enums.StateCode;
import com.landun.market.pojo.model.Category;
import com.landun.market.repository.ICategoryRepository;
import com.landun.market.service.ICategoryService;
import com.landun.market.util.NumberUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 品类维护服务
 *
 * @author jiang.chuan
 * @date 2018-05-05
 */
@Slf4j
@Service
public class CategoryService implements ICategoryService {

    // 排序递增步长
    private static final int RANK_STEP = 10;

    // 默认编号
    private static final int DEFAULT_CODE = 9;

    private final ICategoryRepository categoryRepository;

    @Autowired
    public CategoryService(ICategoryRepository categoryRepository) {
        this.categoryRepository = categoryRepository;
    }


    @Override
    public boolean create(Category category) {
        log.info("待创建的品类：{}", category);

        // 检查名字是否重复
        if (Optional.ofNullable(categoryRepository.countByName(category.getName(), null)).orElse(0) > 0) {
            throw new BusinessException(ResponseCode.DATA_EXISTED, "品类名称", category.getName());
        }

        // 补全其它参数
        category.setParentId(Optional.ofNullable(category.getParentId()).orElse(TOP_PARENT_ID));
        category.setState(Optional.ofNullable(category.getState()).orElse(StateCode.ACTIVE));

        // 如果是顶级
        if (category.getParentId().equals(TOP_PARENT_ID)) {
            category.setLevel(TOP_LEVEL);
        } else {
            Category parent = this.load(category.getParentId());
            if (null == parent) {
                throw new BusinessException(ResponseCode.DATA_NOT_FOUND, "父品类", category.getParentId());
            }
            category.setLevel(parent.getLevel() + 1);
            category.setType(parent.getType());
        }

        // 设置 Rank
        Integer maxRank = Optional.ofNullable(categoryRepository.findMaxRank(category.getParentId())).orElse(RANK_STEP);
        category.setRank(maxRank + RANK_STEP - (maxRank % RANK_STEP));

        // 设置编码
        Integer maxCode = Optional.ofNullable(categoryRepository.findMaxCode(category.getParentId())).orElse(DEFAULT_CODE);
        category.setCode(maxCode + 1);

        Integer results;
        try {
            results = categoryRepository.create(category);
        } catch (Exception ex) {
            log.error("保存品类失败", ex);
            throw new BusinessException(ResponseCode.CREATE_FAILED, "品类");
        }

        log.info("成功创建的品类：{}", category);
        return null != results && results > 0;
    }

    @Override
    @Transactional
    public boolean update(Integer categoryId, Category category) {
        log.info("待修改的品类：{}", category);

        // 检查参数
        if (NumberUtils.isNotPositive(categoryId)) {
            throw new BusinessException(ResponseCode.PARAMETER_REQUIRED, "品类ID");
        }

        if (null == category) {
            throw new BusinessException(ResponseCode.PARAMETER_REQUIRED, "品类");
        }

        // 检查品类是否存在
        Optional.ofNullable(this.load(categoryId))
                .orElseThrow(() -> new DataNotFoundException(ResponseCode.DATA_NOT_FOUND, "待修改的品类", categoryId));

        // 检查名字是否重复
        if (Optional.ofNullable(categoryRepository.countByName(category.getName(), categoryId)).orElse(0) > 0) {
            throw new BusinessException(ResponseCode.DATA_EXISTED, "品类", category.getName());
        }

        // 补全其它参数
        category.setId(categoryId);
        category.setState(Optional.ofNullable(category.getState()).orElse(StateCode.ACTIVE));

        Integer results;
        try {
            results = categoryRepository.update(category);
        } catch (Exception ex) {
            log.error("更新品类失败", ex);
            throw new BusinessException(ResponseCode.UPDATE_FAILED, "品类");
        }

        log.info("成功更新的品类：{}", category);
        return null != results && results > 0;
    }

    @Override
    @Transactional
    public boolean rearrange(Integer topId, Integer bottomId) {
        Map<Integer, Category> categoryMap = this.findByIds(topId, bottomId);
        Category topCat = Optional.ofNullable(categoryMap.get(topId))
                .orElseThrow(() -> new DataNotFoundException("品类(" + topId + ")不存在"));

        Category bottomCat = Optional.ofNullable(categoryMap.get(bottomId))
                .orElseThrow(() -> new DataNotFoundException("品类(" + bottomId + ")不存在"));

        categoryRepository.updateRank(Math.min(topCat.getRank(), bottomCat.getRank()), topId);
        categoryRepository.updateRank(Math.max(topCat.getRank(), bottomCat.getRank()), bottomId);

        return true;
    }

    @Override
    public boolean changeStatus(StateCode stateCode, Integer categoryId) {
        // 检查需要改成什么状态
        if (null == stateCode) {
            throw new BusinessException("品类状态不能为空");
        }

        // ID 不合法
        if (NumberUtils.isNotPositive(categoryId)) {
            throw new BusinessException(ResponseCode.PARAMETER_REQUIRED, "品类ID");
        }

        // 检查品类是否存在
        Optional.ofNullable(this.load(categoryId))
                .orElseThrow(() -> new DataNotFoundException(ResponseCode.DATA_NOT_FOUND, "品类", categoryId));

        // 好吧，前面的状态都检查得差不多了，It's time for 修改状态了
        return Optional.ofNullable(categoryRepository.updateStatus(stateCode.code(), categoryId))
                .map(results -> results > 0)
                .orElse(false);
    }

    @Override
    public Category load(Integer categoryId) {
        if (NumberUtils.isNotPositive(categoryId)) {
            throw new BusinessException(ResponseCode.PARAMETER_REQUIRED, "品类ID");
        }
        return categoryRepository.load(categoryId);
    }

    @Override
    public List<Category> findAll() {
        return categoryRepository.findAll();
    }

    @Override
    public List<Category> findByParent(Integer parentId) {
        if (NumberUtils.isNotPositive(parentId)) {
            throw new BusinessException(ResponseCode.PARAMETER_REQUIRED, "父品类ID");
        }
        return categoryRepository.findByParent(parentId);
    }

    @Override
    public Map<Integer, Category> findByIds(Integer... ids) {
        if (ArrayUtils.isEmpty(ids)) {
            throw new BusinessException(ResponseCode.PARAMETER_REQUIRED, "品类IDs");
        }

        // 将ID去重
        Integer[] categoryIds = Arrays.stream(ids).filter(id -> id != null && id > 0).distinct().toArray(Integer[]::new);
        if (ArrayUtils.isEmpty(categoryIds)) {
            throw new BusinessException(ResponseCode.PARAMETER_REQUIRED, "品类IDs");
        }

        // 根据ID查询
        List<Category> categories = categoryRepository.findByIds(categoryIds);
        if (CollectionUtils.isEmpty(categories)) {
            return new HashMap<>(0);
        }

        // 转换成MAP
        return categories.stream().collect(Collectors.toMap(Category::getId, cat -> cat));
    }

    @Override
    public boolean isNameDuplicated(String name, Integer existedCategoryId) {
        if (StringUtils.isBlank(name)) {
            throw new BusinessException(ResponseCode.PARAMETER_REQUIRED, "品类名称");
        }

        // 检查名字是否重复
        return Optional.ofNullable(categoryRepository.countByName(StringUtils.trimToEmpty(name), existedCategoryId)).orElse(0) > 0;
    }
}
